package com.z1.core.kvutils.map;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.log4j.Logger;

import com.z1.core.PathUtil;
import com.z1.core.io.IOHelper;
import com.z1.core.io.ObjectByte;
import com.z1.core.kvutils.KvFactoryConst;
import com.z1.core.kvutils.KvObject;

public final class KvMap implements KvObject {

	private final Logger logger = Logger.getLogger(getClass());
	
	//键值对
	private ConcurrentHashMap<String, ConcurrentHashMap<String, Object>> kvsMap = null;
	
	//系统配置存储文件（${APP_HOME}/config/keyvalue）
	private final File KV_FILE = new File(PathUtil.getConfDir(), "keyvalue");
	//系统配置存储文件最后修改时间
	private long lastModified = 0L;
	
	private KvMap() {
		logger.info("KvMap path = " + KV_FILE.getAbsoluteFile());
		load();
	}
	
	@SuppressWarnings("unchecked")
	private final void load() {
		if (null == kvsMap) {
			this.kvsMap = new ConcurrentHashMap<String, ConcurrentHashMap<String, Object>>();
		}
		//KV配置文件是否存在,若存在读取
		if (KV_FILE.exists() && KV_FILE.isFile()) {
			//KV配置文件是否有修改（判断最后修改时间）
			//若文件有修改重新读取，反之不做修改
			long newLastModified = KV_FILE.lastModified();
			if (lastModified <= newLastModified) {
				//读取系统配置文件
				Object obj = ObjectByte.toObject(IOHelper.readBytes(KV_FILE));
				//系统配置对象验证：
				//1、若为空，删除KV配置文件
				//2、若对象不为Collection<SysConfig>,删除系统配置文件
				if (null != obj && obj instanceof Map) {
					try {
						kvsMap = (ConcurrentHashMap<String, ConcurrentHashMap<String, Object>>)obj;
					}
					catch (Throwable e) {
						logger.error("load sysconfig err", e);
						deleteKvFile();
					}
				}
				else {
					deleteKvFile();
				}
			}
		}
	}
	
	/**
	 * 删除KV配置文件
	 */
	private final void deleteKvFile() {
		if (KV_FILE.exists() && KV_FILE.isFile()) {
			KV_FILE.delete();
		}
	}
	
	private final void writeKvFile() {
		synchronized (kvsMap) {
			IOHelper.writeBytes(KV_FILE, ObjectByte.toBytes(kvsMap));
			kvsMap = null;
			lastModified = 0L;
			load();
			System.gc();
		}
	}
	
	@Override
	public void set(String group, String key, Object value) {
		synchronized (kvsMap) {
			if (null == group) {
				group = GROUP_DEFAULT;
			}
			ConcurrentHashMap<String, Object> groupMap = kvsMap.get(group);
			if (null == groupMap) {
				groupMap = new ConcurrentHashMap<String, Object>();
			}
			groupMap.put(key, value);
			kvsMap.put(group, groupMap);
			writeKvFile();
		}
	}
	
	@Override
	public List<String> groups() {
		List<String> groups = new ArrayList<String>();
		for (String key : kvsMap.keySet()) {
			groups.add(key);
		}
		return groups;
	}

	@Override
	public Map<String, Object> get(String group) {
		if (null == group) {
			group = GROUP_DEFAULT;
		}
		return kvsMap.get(group);
	}
	
	@Override
	public int count(String group) {
		if (null == group) {
			group = GROUP_DEFAULT;
		}
		ConcurrentHashMap<String, Object> map = kvsMap.get(group);
		return null == map ? 0 : map.size();
	}
	
	@Override
	public Object get(String group, String key) {
		if (null == group) {
			group = GROUP_DEFAULT;
		}
		ConcurrentHashMap<String, Object> groupMap = kvsMap.get(group);
		if (null == groupMap) {
			return null;
		}
		return groupMap.get(key);
	}
	
	@Override
	public void remove(String group, String key) {
		if (null == group) {
			group = GROUP_DEFAULT;
		}
		if (null != kvsMap.get(group)) {
			kvsMap.get(group).remove(key);
		}
	}

	@Override
	public String type() {
		return KvFactoryConst.KV_MAP;
	}
	
	private static KvMap kvObject = null;
	public static final KvMap getInstance() {
		if (null == kvObject) {
			kvObject = new KvMap();
		}
		return kvObject;
	}

}
